<?php
/*
 * mathcode.class.php
 * 验证码类
 */

class mathcode
{
/**
* 验证码
* char: 字符
* angle: 字符偏移的角度(-30<=angle<=30)
* color: 字符颜色
*
* @var array
* @access private
*/
	var $code = array();

/**
* 字体信息
* //space: 字符间隔(px)
* //size: 字体大小(px)
* left: 第一个字符距离图像最左边的象素(px)
* //top: 字符距离图像最上边的象素(px)
* file: 字体文件的路径
*
* @var array
* @access private
*/
	var $font = array();

/**
* 图像信息
* type: 图像类型
* mime: MIME类型
* width: 图像的宽(px)
* height: 图像高(px)
* func: 创建图像的方法
*
* @var array
* @access private
*/
	var $image = array();

/**
* 干扰信息
* type: 干扰类型(false表示不使用)
* density: 干扰密度
*
* @var array
* @access private
*/
	var $molestation = array();

/**
* 背景色(RGB)
* r: 红色(0-255)
* g: 绿色(0-255)
* b: 蓝色(0-255)
*
* @var array
* @access private
*/
	var $bg_color = array();

/**
* 默认前景色(RGB)
* r: 红色(0-255)
* g: 绿色(0-255)
* b: 蓝色(0-255)
*
* @var array
* @access private
*/
	var $fg_color = array();

/**
 * 验证码运算结果
 *
 * @var string
 */
	var $mathresult = '';

/**
 * 背景颜色模式
 *
 * @var boolean 是否渐变
 */
	var $bgmode = '';
	
/**
* 构造函数，初始化各变量
*
* @access public
*/
	function __construct()
	{
		$this->setCode();
		$this->setMolestation();
		$this->setImage();
		$this->setFont();
		$this->setBgColor();
		$this->setBgmode();
	}

/**
* 获取产生的mathcode
* 
*/
	function getcode()
	{
		return $this->mathresult;
	}

/**
* 绘制图像
*
* @access public
* @param string 文件名,留空表示输出到浏览器
* @return void
*/
	function display($filename='')
	{
		//创建空白图像
		$im = imagecreatetruecolor($this->image['width'], $this->image['height']);

		//设置图像背景
		$bg_color=imagecolorallocate($im,$this->bg_color['r'], $this->bg_color['g'], $this->bg_color['b']);
		imagefilledrectangle($im, 0, 0, $this->image['width'],	$this->image['height'], $bg_color);

		//背景渐变
		if($this->bgmode)
		{
			for($i=0; $i<$this->image['width']; $i++)
			{
				$alpha = round($i/($this->image['width']/127)) + 30;
				if($alpha >= 128) { $alpha = 127; }
				$alpha_color = imagecolorallocatealpha($im, 200, 200, 200, $alpha);
				imagefilledrectangle($im, $i, 0, ($i+1), ($this->image['height']-1), $alpha_color);
			}
		}
		
		//生成验证码 array
		$code = $this->generateCode();
		
		//将验证码画到图像中
		$current_left = $this->font['left'];

		for($i=0; $i<4; $i++)
		{
			$font_color = imagecolorallocate($im, $code[$i]['color']['r'], $code[$i]['color']['g'], $code[$i]['color']['b']);
			imagettftext($im, $code[$i]['size'], $code[$i]['angle'], $current_left,
			$code[$i]['top'],$font_color, $this->font['file'], iconv("gb2312", "UTF-8", $code[$i]['char']));
			$current_left += $code[$i]['size']+$code[$i]['space'];
		}

		//绘制图像干扰
		$this->paintMolestation($im);

		//输出
		if(isset($filename) && $filename != '')
		{
			$this->image['func']($im, $filename.'.'.$this->image['type']);
		}
		else
		{
			header("Expires: -1");
			header("Cache-Control:no-cache,must-revalidate");
			header("Pragma: no-cache");
			header("Content-type:".$this->image['mime']);
			$this->image['func']($im);
		}
		imagedestroy($im);
	}

/**
* 生成随机验证码
*
* @access private
* @return array生成的验证码
*/
	function generateCode()
	{
		//获取参与运算的数字
		$number = array(0,1,2,3,4,5,6,7,8,9);
		
		//生成随机字符串
		mt_srand((double)microtime()*1000000);
		//运算规则
		$rule = array('+', '-', '*', '/');
		$rule_replace = array('加上', '减去', '乘以', '除以', '等于');
		$code = array();
		$index = 0;
		
		for($i=0; $i<4; $i++)
		{
			if($i%2 == 0)
			{
				$index = mt_rand(0, count($number)-1);
				$code[$i]['char'] = $number[$index];
				$code[$i]['size'] = mt_rand(20, 30);
				$code[$i]['space'] = mt_rand(5, 10);
				$code[$i]['top'] = mt_rand(35, 40);
			}
			elseif($i == 1)
			{
				$rule_mark = mt_rand(0, 3);
				$code[$i]['char'] = $rule_replace[$rule_mark];
				$code[$i]['rule'] = $rule[$rule_mark];
				$code[$i]['size'] = mt_rand(12, 20);
				$code[$i]['space'] = 40;
				$code[$i]['top'] = mt_rand(30, 40);
			}
			elseif ($i == 3)
			{
				$code[$i]['char'] = $rule_replace['4'];
				$code[$i]['size'] = mt_rand(12, 18);
				$code[$i]['space'] = 40;
				$code[$i]['top'] = mt_rand(30, 40);
			}
			if($this->code['deflect'])
			{
				$code[$i]['angle'] = mt_rand(-15, 15);
			}
			else
			{
				$code[$i]['angle'] = 0;
			}
			if($this->code['multicolor'])
			{
				$code[$i]['color']['r'] = mt_rand(0, 180);
				$code[$i]['color']['g'] = mt_rand(0, 180);
				$code[$i]['color']['b'] = mt_rand(0, 180);
			}
			else
			{
				$code[$i]['color']['r'] = $this->fg_color['r'];
				$code[$i]['color']['g'] = $this->fg_color['g'];
				$code[$i]['color']['b'] = $this->fg_color['b'];
			}
			
		}
		//生成的验证码运算结果
		switch ($code['1']['rule'])
		{
			case '+':
				$this->mathresult = $code['0']['char'] + $code['2']['char'];
				break;
				
			case '-':
				$this->mathresult = abs($code['0']['char'] - $code['2']['char']);
				break;
				
			case '*':
				$this->mathresult = $code['0']['char'] * $code['2']['char'];
				break;
				
			case '/':
				$this->mathresult = round($code['0']['char'] / $code['2']['char']);
				break;
		}

		return $code;
	}

/**
* 获取图像类型
*
* @access private
* @param string 扩展名
* @return [mixed] 错误时返回false
*/
	function getImageType($extension)
	{
		switch(strtolower($extension))
		{
			case 'png':
				$information['mime'] = image_type_to_mime_type(IMAGETYPE_PNG);
				$information['func'] = 'imagepng';
				break;
			case 'gif':
				$information['mime'] = image_type_to_mime_type(IMAGETYPE_GIF);
				$information['func'] = 'imagegif';
				break;
			case 'wbmp':
				$information['mime'] = image_type_to_mime_type(IMAGETYPE_WBMP);
				$information['func'] = 'imagewbmp';
				break;
			case 'jpg':
				$information['mime'] = image_type_to_mime_type(IMAGETYPE_JPEG);
				$information['func'] = 'imagejpeg';
				break;
			case 'jpeg':
				$information['mime'] = image_type_to_mime_type(IMAGETYPE_JPEG);
				$information['func'] = 'imagejpeg';
				break;
			case 'jpe':
				$information['mime'] = image_type_to_mime_type(IMAGETYPE_JPEG);
				$information['func'] ='imagejpeg';
				break;
			default:
				$information = false;
				break;
		}
		return $information;
	}

/**
* 绘制图像干扰元素
*
* @access private
* @param resource 图像资源
* @return void
*/
	function paintMolestation(&$im)
	{
		//总象素
		$num_of_pels = ceil($this->image['width']*$this->image['height']/5);

		switch($this->molestation['density'])
		{
			case 'fewness':
				$density = ceil($num_of_pels/5);
				break;
			case 'muchness':
				$density = ceil($num_of_pels/2);
				break;
			case 'normal':
				$density = ceil($num_of_pels/3);
				break;
			default:
				break;
		}

		switch($this->molestation['type'])
		{
			case 'point':
				$density = ceil($density/2);
				$this->paintPoints($im, $density);
				break;
			case 'line':
				$density = ceil($density/120);
				$this->paintLines($im, $density);
				break;
			case 'both':
				$density = ceil($density/2);
				$this->paintPoints($im, $density);
				$density = ceil($density/80);
				$this->paintLines($im, $density);
				break;
			default:
				break;
		}
	}

/**
* 画点
*
* @access private
* @param resource 图像资源
* @param int 图像资源
* @return void
*/
	function paintPoints(&$im,$quantity)
	{
		mt_srand((double)microtime()*1000000);

		for($i=0; $i<$quantity; $i++)
		{
			$randcolor = imagecolorallocate($im,mt_rand(0,255),	mt_rand(0,255), mt_rand(0,255));
			imagesetpixel($im,mt_rand(0, $this->image['width']), mt_rand(0, $this->image['height']), $randcolor);
		}
	}

/**
* 画线
*
* @access private
* @param resource 图像资源
* @param int 图像资源
* @return void
*/
	function paintLines(&$im,$quantity)
	{
		mt_srand((double)microtime()*1000000);

		for($i=0; $i<$quantity; $i++)
		{
			$randcolor = imagecolorallocate($im,mt_rand(0,255),	mt_rand(0,255), mt_rand(0,255));
			$thickness = mt_rand(1,3);
			imagesetthickness($im, $thickness);
			imageline($im, mt_rand(0, $this->image['width']), mt_rand(0, $this->image['height']),
				mt_rand(0, $this->image['width']), mt_rand(0, $this->image['height']),$randcolor);
		}
	}

/**
* 设置干扰信息
*
* @access public
* @param array 干扰信息
* type string 干扰类型(选项:false,'point','line')
* density string 干扰密度(选项:'normal','muchness','fewness')
* @return void
*/
	function setMolestation($molestation='')
	{
		if(is_array($molestation))
		{
			if(!in_array($molestation['type'], array('both', 'point', 'line')))
			{
				$molestation['type'] = 'both';
			}
			if(!in_array($molestation['density'], array('normal', 'fewness', 'muchness')))
			{
				$molestation['density'] = 'normal';
			}
			$this->molestation = $molestation;
		}
		else
		{
			$this->molestation = array(
				'type' => 'line',
				'density' => 'normal'
			);
		}
	}

/**
* 设置前景色
*
* @access private
* @param array RGB颜色
* @return void
*/
	function setFgColor($color)
	{
		if(is_array($color) && is_integer($color['r']) &&	is_integer($color['g']) && is_integer($color['b']) &&
			($color['r'] >= 0 && $color['r'] <= 255) && ($color['g'] >= 0 && $color['g'] <= 255) &&	($color['b'] >= 0 && $color['b'] <= 255))
		{
			$this->fg_color = $color;
		}
		else
		{
			$this->fg_color = array('r' => 0,'g' => 0,'b' => 0);
		}
	}

/**
* 设置背景色
*
* @access public
* @param array RGB颜色
* @return void
*/
	function setBgColor($color='')
	{
		if(is_array($color) && is_integer($color['r']) &&
		is_integer($color['g']) && is_integer($color['b']) &&
		($color['r']>=0 && $color['r']<=255) &&
		($color['g']>=0 && $color['g']<=255) &&
		($color['b']>=0 && $color['b']<=255))
		{
			$this->bg_color = $color;
		}
		else
		{
			$this->bg_color = array('r'=>255,'g'=>255,'b'=>255);
		}

		//设置默认的前景色,与背景色相反
		$fg_color=array(
			'r' => 255-$this->bg_color['r'],
			'g' => 255-$this->bg_color['g'],
			'b' => 255-$this->bg_color['b']
		);
		$this->setFgColor($fg_color);
	}

/**
* 设置背景色模式
*
* @access public
* @param boolean 是否渐变
* @return void
*/

	function setBgmode($bgmode = true)
	{
		$this->bgmode = $bgmode ? true : false;
	}

/**
* 设置验证码
*
* @access public
* @param array 字符信息
* deflect boolean 字符是否偏转
* multicolor boolean 字符是否彩色
* @return void
*/
	function setCode($code='')
	{
		if(is_array($code))
		{
			if(!is_bool($code['deflect']))
			{
				$code['deflect'] = true;
			}
			if(!is_bool($code['multicolor']))
			{
				$code['multicolor'] = true;
			}
		}
		else
		{
			$code = array('deflect' => true,'multicolor' => true);
		}
		$this->code = $code;
	}

/**
* 设置字体信息
*
* @access public
* @param array 字体信息
* space int 字符间隔(px)
* size int 字体大小(px)
* left int 第一个字符距离图像最左边的象素(px)
* top int 字符距离图像最上边的象素(px)
* file string 字体文件的路径
* @return void
*/
	function setFont($font='')
	{
		if(is_array($font))
		{
			if(!is_integer($font['left']) || $font['left'] < 0 || $font['left'] > $this->image['width'])
			{
				$font['left'] = 10;
			}

			if(!file_exists($font['file']))
			{
				$font['file'] = 'include/fonts/simsun.ttc';
			}
			$this->font = $font;
		}
		else
		{
			$this->font = array(
			'left' => 10,
			'file' => 'include/fonts/simsun.ttc');
		}
	}

/**
* 设置图像信息
*
* @access public
* @param array 图像信息
* typestr ing 图像类型(选项:'png','gif','wbmp','jpg')
* width int 图像宽(px)
* height int 图像高(px)
* @return void
*/
	function setImage($image='')
	{
		if(is_array($image))
		{
			if(!is_integer($image['width']) || $image['width'] <= 0)
			{
				$image['width'] = 200;
			}
			if(!is_integer($image['height']) || $image['height'] <= 0)
			{
				$image['height'] = 50;
			}
			$this->image = $image;
			$information=$this->getImageType($image['type']);
			if(is_array($information))
			{
				$this->image['mime'] = $information['mime'];
				$this->image['func'] = $information['func'];
			}
			else
			{
				$this->image['type'] = 'png';
				$information = $this->getImageType('png');
				$this->image['mime'] = $information['mime'];
				$this->image['func'] = $information['func'];
			}
		}
		else
		{
			$information = $this->getImageType('png');
			$this->image = array(
				'type' => 'png',
				'mime' => $information['mime'],
				'func' => $information['func'],
				'width' => 200,
				'height' => 50);
		}
	}

}
?>